/*
 * Copyright (c) 2024 Black Sesame Technologies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <csignal>
#include <thread>
#include <iostream>
#include <unistd.h>
#include <unordered_map>
#include <typeinfo>
#include "dal/topic.h"
#include "dal/client.h"
#include "dal/domain_participant.h"
#include "dal/identifier.h"
#include "dal/config_loader.h"
#include "my_package/msg/all_type.hpp"
#include "my_package/msg/all_type_under.hpp"

volatile sig_atomic_t g_signal_received = false;

void signal_handler(int signal)
{
    g_signal_received = true;
}

static void reg_sigs()
{
    std::signal(SIGINT, signal_handler);
    std::signal(SIGILL, signal_handler);
    std::signal(SIGABRT, signal_handler);
    std::signal(SIGSEGV, signal_handler);
    std::signal(SIGTERM, signal_handler);
    std::signal(SIGBUS, signal_handler);
}

void on_response_callback(const void* user_data)
{
    dal_client_t* client = (dal_client_t*)user_data;

    dal_service_info_t header;
    my_package::msg::AllType response;
    bool taken = false;
    dal_ret_t ret = dal_client_take_response(client, &header, &response, &taken);
    if (DAL_RETCODE_OK != ret) {
        std::cout << "take response failed, ret: " << ret << std::endl;
        return;
    }

    if (taken) {
        std::cout << "response taken:" << std::endl;
        std::cout << "    response.i8 = " << (int32_t)response.i8 << std::endl;
        std::cout << "    response.i16 = " << response.i16 << std::endl;
        std::cout << "    response.i32 = " << response.i32 << std::endl;
        std::cout << "    response.i64 = " << response.i64 << std::endl;
        std::cout << "    response.u8 = " << (int32_t)response.u8 << std::endl;
        std::cout << "    response.u16 = " << response.u16 << std::endl;
        std::cout << "    response.u32 = " << response.u32 << std::endl;
        std::cout << "    response.u64 = " << response.u64 << std::endl;
        std::cout << "    response.f32 = " << response.f32 << std::endl;
        std::cout << "    response.f64 = " << response.f64 << std::endl;
        std::cout << "    response.str = " << response.str << std::endl;
    }
}

int main(int argc, char* argv[])
{
#if defined(__x86_64__)
    std::string prefix = "/opt/cyber/usr/bin/dal/TestCases/Helloworld/conf/";
#elif defined(__android_aarch64__)
    std::string prefix = "/vendor/etc/dal/conf/";
#else
    std::string prefix = "/usr/bin/autoplt/demos/bst-hanhai-dal-demo/HelloWorld/conf/";
#endif
    std::string fastdds_conf_path = prefix + "dal_fastdds_profiles.xml";
    std::string cyclonedds_conf_path = prefix + "dal_cyclonedds_config.xml";
    std::string rtidds_conf_path = prefix + "DAL_RTI_USER_QOS_PROFILES.xml";

    std::unordered_map<std::string, const char*> conf_file_path_map = {
        {DAL_FASTDDS_IDENTIFIER, fastdds_conf_path.c_str()},
        {DAL_CYCLONEDDS_IDENTIFIER, cyclonedds_conf_path.c_str()},
        {DAL_RTICONNEXTDDS_IDENTIFIER, rtidds_conf_path.c_str()}};

    reg_sigs();

    dal_load_config_from_path(conf_file_path_map.at(dal_get_identifier()), nullptr);
    // create participant
    dal_domain_participant_t* part = dal_create_domain_participant_with_profile(
        20, DAL_PARTICIPANT_QOS_DEFAULT, "dal_testcase_participant_profile", NULL, 0);

    // register type
    dal_type_support_t* ts =
        dal_create_type_support((void*)(my_package::msg::AllType::FullyQualifiedName()));
    dal_type_support_register_type(ts, part, dal_type_support_get_type_name(ts));

    dal_client_t* client =
        dal_domain_participant_create_client(part,
                                              "HelloWorldService",
                                              dal_type_support_get_type_name(ts),
                                              dal_type_support_get_type_name(ts),
                                              DAL_DATAWRITER_QOS_DEFAULT,
                                              DAL_DATAREADER_QOS_DEFAULT);

    if (!client) {
        std::cout << "create client failed" << std::endl;
        return -1;
    }

    // set on response callback
    dal_client_set_on_response_callback(client, on_response_callback, client);

    // waiting for server is ready.
    while (true) {
        bool ready = false;
        dal_client_check_server_is_available(client, &ready);
        if (ready) {
            break;
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        std::cout << "wating for server..." << std::endl;
    }

    int32_t cnt = 0;
    my_package::msg::AllType request;
    while (!g_signal_received) {
        request.i8 = cnt;
        request.i16 = cnt;
        request.i32 = cnt;
        request.i64 = cnt;
        request.u8 = cnt;
        request.u16 = cnt;
        request.u32 = cnt;
        request.u64 = cnt;
        request.f32 = cnt;
        request.f64 = cnt;
        request.str = "request";
        dal_ret_t ret = dal_client_send_request(client, &request);
        if (ret != DAL_RETCODE_OK) {
            std::cout << "send request failed, ret: " << ret << std::endl;
        } else {
            std::cout << "send request success" << std::endl;
        }
        cnt++;
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }

    dal_delete_type_support(ts);
    dal_domain_participant_delete_client(part, client);
    dal_delete_domain_participant(part);
}